package sim1011.poltergeist;

import jade.core.AID;
import jade.core.Agent;
import jade.core.behaviours.OneShotBehaviour;
import jade.core.behaviours.ParallelBehaviour;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.lang.acl.ACLMessage;
import sim1011.behaviours.ESPPhotographerBehaviour;
import sim1011.behaviours.MobileNodeMoverBehaviour;
import sim1011.behaviours.PoltergeistMainBehaviour;
import sim1011.starter.EctoMobileStarter;
import sim1011.starter.Logger;
import sim1011.status.Status;

public class Poltergeist extends Agent implements java.io.Serializable {
	private static final long serialVersionUID = -3343895735989562176L;
	private Arbiter migrationArbiter;
	private Status status;

	public Status getStatus() {
		return status;
	}

	public String requestMigrationDecision(String containerID,
			String componentName) {
		return migrationArbiter.makeDecision(componentName, containerID);
		//return migrationArbiter.decide(containerID, componentName);
	}

	public String requestMigrationDecisionOnLowBattery(String containerID,
			String componentName) {
		return migrationArbiter.decideOnLowBattery(containerID, componentName);
	}

	public void roam() {
		status.roam(EctoMobileStarter.MOBILE_NODE_NAME);
	}

	public void setStatus(Status status) {
		this.status = status;
	}

	@SuppressWarnings("serial")
	public void setup() {
		Logger.log("[POLTERGEIST] Parte il poltergeist");
		// Registra poltergeist
		DFAgentDescription dfd = new DFAgentDescription();
		dfd.setName(getAID());
		ServiceDescription sd = new ServiceDescription();
		sd.setType("ecto-poltergeist");
		sd.setName("ecto-poltergeist");
		dfd.addServices(sd);
		try {
			DFService.register(this, dfd);
		} catch (FIPAException fe) {
			fe.printStackTrace();
		}
		// inizializza lo stato che gli viene passato dall' esterno
		// aggiungi i behaviour
		ParallelBehaviour main = new ParallelBehaviour();
		main.addSubBehaviour(new PoltergeistMainBehaviour());
		main.addSubBehaviour(new MobileNodeMoverBehaviour(this,
				EctoMobileStarter.MOVE_NODE_TIME));
		main.addSubBehaviour(new ESPPhotographerBehaviour(this,
				EctoMobileStarter.PHOTO_TIME));
		migrationArbiter = new Arbiter(status);
		/*
		 * stampa del mapping Iterator<String> iter =
		 * status.getWhereAreComponents().keySet().iterator();
		 * System.out.println("MAPPING INIZIALE COMPONENTE NODO");
		 * while(iter.hasNext()){ String componentName = iter.next(); String
		 * nodeName = status.getWhereAreComponents().get(componentName);
		 * System.out.println(componentName+" sul nodo "+nodeName);
		 * 
		 * }
		 */

		addBehaviour(main);
		addBehaviour(new OneShotBehaviour() {

			@Override
			public void action() {
				// Find all Components
				DFAgentDescription template = new DFAgentDescription();
				ServiceDescription sd = new ServiceDescription();
				sd.setType("ecto-components");
				template.addServices(sd);
				try {
					DFAgentDescription[] result = DFService.search(myAgent,
							template);
					AID[] cmp = new AID[result.length];
					for (int i = 0; i < result.length; ++i) {
						cmp[i] = result[i].getName();
					}
					// se ce ne sono scegline i primi k e mandagli il messaggio
					// di start.
					if (cmp.length > 0) {
						int k = Math.round(EctoMobileStarter.NUM_COMPONENTS/2);
						System.out
								.println("Chosed " + k + " components to run");
						for (int i = 0; i < k; ++i) {
							ACLMessage startUP = new ACLMessage(ACLMessage.CFP);
							AID receiver = cmp[i];
							startUP.addReceiver(receiver);
							status.increaseOutcomingMessagesToPoltergeist();
							myAgent.send(startUP);
						}
					}
				} catch (FIPAException e) {
					e.printStackTrace();
				}
			}
		});
	}

	protected void takeDown() {
		// Deregistra poltergeist
		try {
			DFService.deregister(this);
		} catch (FIPAException fe) {
			fe.printStackTrace();
		}
	}
}